﻿using System;
using NUnit.Framework;

using Supremacy.Economy;
using Supremacy.Game;
using Supremacy.Universe;

namespace Supremacy.Tests.SupremacyCore.Universe
{

    /// <summary>
    /// Unit Tests for Supremacy.Universe.Colony
    /// 
    /// NOTE:   These tests rely on deactivating the existing buildings on any randomly created game
    ///         If a new game is created with buildings that are always active (Engery Cost = 0) then the buildings
    ///         will need to be removed, instead of simply deactivated
    /// </summary>
    [TestFixture]
    public class ColonyTest : IDisposable
     {

        /// <summary>
        /// Return a new building Design
        /// </summary>
        /// <param name="EnergyCost">The energy cost of the new design</param>
        /// <param name="BonusType">Design Bonus Type</param>
        /// <param name="Amount">Bonus Type Amount</param>
        /// <returns>A new building deisgn.</returns>
        private static Buildings.BuildingDesign GetDesign(int EnergyCost, BonusType BonusType, int Amount)
        {
            var Design = new Buildings.BuildingDesign
                         {
                             DesignID = Supremacy.Game.GameContext.Current.TechDatabase.GetNewDesignID()
                         };

            Design.Key = Design.DesignID.ToString();
            Design.EnergyCost = EnergyCost;

            Design.Bonuses.Add(new Bonus(BonusType, Amount));

            Supremacy.Game.GameContext.Current.TechDatabase.Add(Design);

            return Design;
        }

        public GameContext Game;

        /// <summary>
        /// Construct a Colony for Testing
        /// </summary>
        public ColonyTest()
        {
            Environment.CurrentDirectory = @"..\..\..\SupremacyClient\bin\Debug\";
            AppDomain.CurrentDomain.SetData("DataDirectory", Environment.CurrentDirectory);

            var players = new System.Collections.Generic.List<Player>();

            PlayerContext.Current = new PlayerContext(players);
            Game = GameContext.Create(new GameOptions(), false);

            var localPlayer = new Player
            {
                EmpireID = 0,
                PlayerID = 0,
                Name = "TestDriver"
            };

            players.Add(localPlayer);

            new GameEngine().DoPreGameSetup(Game);

            GameContext.Push(Game);
        }


        #region IDisposable Members

        private Boolean Disposed;

        public void Dispose()
        {
            if (!Disposed) { Disposed = true;  Supremacy.Game.GameContext.Pop(); }
        }

        #endregion

        /// <summary>
        /// Simple accessor that allows us to loop through every Colony in our current game
        /// </summary>
        /// <returns>An array of colonies</returns>
        public Colony[] Colonies 
        {
            get { return new System.Collections.Generic.List<Colony>(Game.Universe.Find<Colony>()).ToArray(); }
        }

        /// <summary>
        /// Add a new Colony
        /// </summary>
        /// <returns>Return a Colony</returns>
        public Colony AddNewColony()
        {
            var BaseColony = Colonies[0];

            return new Colony(BaseColony.System, BaseColony.Inhabitants);
        }

        #region Constructor Tests

        /// <summary>
        /// Check <see cref="ArgumentNullException"/> is raised when attemping to construct a Colony with a null System
        /// </summary>
        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void SetColonyConstructorWithNullSystem()
        {
            new Colony(null, new Entities.Race());
        }

        /// <summary>
        /// Check <see cref="ArgumentNullException"/> is raised when attemping to construct a Colony with a null Race
        /// </summary>
        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void SetColonyConstructorWithNullRace()
        {
            new Colony(new StarSystem(), null);
        }

        /// <summary>
        /// Make sure that when constructing a colony all fields are correctly initialized
        /// Note:   This test is a little lazy. It uses reflection to retrive all private fields
        ///         and check that they are not null. 
        ///         The test does not check fields in child any base classes. 
        ///         This does not mean the value is valid, just that it has been initialized
        /// </summary>
        [Test]
        public void testColonyConstructorFieldsInitialized()
        {
            foreach (var Colony in this.Colonies)
            {
                foreach (var Field in Colony.GetType().GetFields(
                                                    System.Reflection.BindingFlags.Instance |
                                                    System.Reflection.BindingFlags.NonPublic |
                                                    System.Reflection.BindingFlags.DeclaredOnly
                                                    ))
                { Assert.IsNotNull(Field.GetValue(Colony), "Field Name: " + Field.Name); }
            }
        }

        #endregion

        /// <summary>
        /// Check that the returned value of every property in the Colony Class is a non-null object
        /// Note:   This test is a little lazy. It uses reflection to retrive all properties
        ///         and check that they are not null. 
        ///         The test does not check properties in base classes. 
        ///         This does not mean the value is valid, just that it is non-null!
        /// </summary>
        [Test]
        public void testPropertiesNotNull()
        {
            var Properties = typeof(Colony).GetProperties(
                                                 System.Reflection.BindingFlags.Instance |
                                                 System.Reflection.BindingFlags.NonPublic |
                                                 System.Reflection.BindingFlags.DeclaredOnly);

            foreach (var Colony in this.Colonies)
            {
                foreach (var Property in Properties)
                { Assert.IsNotNull(Property.GetValue(Colony, null), "Property Name: " + Property.Name); }
            }
        }

        /// <summary>
        /// Check that the ObjectType is correctly returned as a Colony
        /// </summary>
        [Test]
        public void isObjectTypeColony()
        {
            foreach (var Colony in this.Colonies)
            {
                Assert.AreEqual(Colony.ObjectType, UniverseObjectType.Colony);
            }
        }

        /// <summary>
        /// Make sure that when creating a Colony the Correct Original StarSystemOwner is returned
        /// </summary>
        [Test]
        public void checkOriginalOwner()
        {
            foreach (var Colony in this.Colonies)
            {
                Assert.IsNotNull(Colony.OriginalOwner); //Just check that an ownwer has actually been set!
                Assert.AreEqual(Colony.OriginalOwner, Colony.Owner);
            }         
        }

        /// <summary>
        /// Make sure that if we modify the Colony owner the original is not modified
        /// </summary>
        [Test]
        public void checkOriginalOwnerDoesNotChange()
        {
            //I do not want to modify the 'base' colonies collection here, so I will create a new Colony Test.

            using (var CTest = new ColonyTest())
            {
                foreach (var Colony in CTest.Colonies)
                {
                    var OrigCiv = Colony.OriginalOwner;

                    Entities.Civilization NewCiv = null;

                    for (int i = 0; i < CTest.Game.Civilizations.Count - 1; i++)
                    {
                        if (CTest.Game.Civilizations[i] != OrigCiv) { NewCiv = CTest.Game.Civilizations[i]; break; }
                    }

                    Assert.IsNotNull(NewCiv); //This is just part of the test. Make sure we have a new civilization
                    Assert.AreNotEqual(OrigCiv, NewCiv);

                    Colony.Owner = NewCiv;

                    Assert.AreEqual(Colony.Owner, NewCiv);
                    Assert.AreEqual(Colony.OriginalOwner, OrigCiv);
                }
            }
        }

        /// <summary>
        /// Test that the calculated Growth Rate = the expected Growth Rate
        /// Based on the current calculation this test assumes the following rules
        /// 
        /// 1. The Growth Rate is a based upon the Growth Rate of the Star System
        /// 2. Each Active Building with a bonus can modify the growth rate
        /// 
        /// NOTE:   This test, like the code it tests, does not deal with rounding in any great detail.
        ///         There is potential for rounding errors to be introducted 
        /// </summary>
        [Test]
        public void checkGrowthRate() 
        {
            using (var CTest = new ColonyTest())
            {
                foreach (var Colony in CTest.Colonies)
                {
                    //Disable all buildings
                    foreach (var building in Colony.Buildings) { building.IsActive = false; }
                    //Check that the growth rate is = to the Colony Growth Rate.

                    Decimal SystemRate = Decimal.Round(Colony.System.GetGrowthRate(Colony.Inhabitants).ToDecimal(null), 2);
                    Decimal ColonyRate = Decimal.Round(Colony.GrowthRate.ToDecimal(null), 2);

                    Assert.AreEqual(SystemRate, ColonyRate);

                    //Now let us add our own active Building
                    //This building should have no impact
                    Colony.AddBuilding(new Buildings.Building(GetDesign(0,
                        BonusType.AntiShipDefense, 0)));

                    Assert.AreEqual(SystemRate, ColonyRate); //Should not have changed

                    //Add a building with a GrowthRate of 10
                    Colony.AddBuilding(new Buildings.Building(GetDesign(0,
                        BonusType.GrowthRate, 10)));

                    //This building adds a GrowthRate of 10
                    ColonyRate = (SystemRate + 0.1M);

                    Assert.AreEqual(ColonyRate, Decimal.Round(Colony.GrowthRate.ToDecimal(null), 2));

                    Colony.AddBuilding(new Buildings.Building(GetDesign(0,
                        BonusType.PercentGrowthRate, 20)));

                    //Our new building adds a growth rate of 2%
                    ColonyRate = Decimal.Round(0.01M * ((decimal)(Colony.System.GetGrowthRate(Colony.Inhabitants) * 100) +
                        ((decimal)(Colony.System.GetGrowthRate(Colony.Inhabitants) * 100) * 0.2M) + 10), 2);

                    Assert.AreEqual(ColonyRate, Decimal.Round(Colony.GrowthRate.ToDecimal(null), 2));
                } //foreach (var Colony in CTest.Colonies)
            }
        } //public void checkGrowthRate() 

        /// <summary>
        /// Confirm that the Colony MaxPopulation matches the expected value
        /// 
        /// The maximum population for a Colony is determined by the number of planets in a system
        /// and the number of moons each planet can have
        /// and the number of active buildings that modify a moons maximum population 
        /// </summary>
        [Test]
        [Ignore("TODO: Check these calculations.")]
        public void checkMaxPopulation()
        {
            //var Colony = this.GetColonyInstance();

            //As with the the GrowthRate test this test relies too heavily on underlying objects
            //that should be tested first (StarSystem, Planet)
            Assert.Fail("Not Implemented");
        }

        /// <summary>
        /// Confirm that when Get/Set Colony we have a valid Object
        /// 
        /// One possible improvement to the Colony.OwnerID would be to check the OwnerID is actually valid
        /// </summary>
        [Test]
        public void testGetSetOwner()
        {
            using (var CTest = new ColonyTest())
            {
                foreach (var Colony in CTest.Colonies)
                {
                    var OrigCiv = Colony.OriginalOwner; //this should not change during this test

                    Assert.IsNotNull(Colony.OwnerID); //Check we have an initial owner

                    //Test setting with an invalid value
                    Colony.OwnerID = Entities.Civilization.InvalidID;
                    Assert.AreEqual(Entities.Civilization.InvalidID, Colony.OwnerID);

                    //Assert that the original owner has not changed
                    Assert.AreEqual(Colony.OriginalOwner, OrigCiv);

                    Entities.Civilization NewCiv = null;

                    for (int i = 0; i < CTest.Game.Civilizations.Count - 1; i++)
                    {
                        if (CTest.Game.Civilizations[i] != OrigCiv) { NewCiv = CTest.Game.Civilizations[i]; break; }
                    }

                    Assert.IsNotNull(NewCiv); //This is just part of the test. Make sure we have a new civilization
                    Assert.AreNotEqual(OrigCiv, NewCiv);

                    if (NewCiv == null)
                        continue;
                    
                    Colony.OwnerID = NewCiv.CivID;

                    Assert.AreEqual(Colony.OwnerID, NewCiv.CivID);
                    Assert.AreEqual(Colony.System.OwnerID, NewCiv.CivID); //Check that we have updated the CIVID
                }
            }
        }

        /// <summary>
        /// Colony::Name test
        /// 
        /// Make sure the Colony property returns null
        /// Make sure that the system name correctly returns
        /// Check that the colony name returns
        /// </summary>
        [Test]
        public void testColonyName()
        {
            using (var CTest = new ColonyTest())
            {
                foreach (var Colony in CTest.Colonies)
                {
                    Assert.IsNotNull(Colony.Name); //Initial COlony name should be valid

                    Colony.Name = "ColonyName";
                    Assert.AreEqual(Colony.Name, "ColonyName");
                }
            }
        }

        /// <summary>
        /// Colony::Shipyard
        /// Check the Shipyard property
        /// </summary>
        [Test]
        public void testColonyShipyard()
        {
            using (var CTest = new ColonyTest())
            {
                foreach (var Colony in CTest.Colonies)
                {
                    //Add a new shipgard if one does not exist
                    if (Colony.Shipyard == null)
                    {
                        var Shipyard = new Orbitals.Shipyard();
                        Supremacy.Game.GameContext.Current.Universe.Objects.Add(Shipyard);

                        Colony.Shipyard = Shipyard;
                        Assert.AreEqual(Colony.Shipyard, Shipyard);

                        //Check that the Colony PropertyChanged event is raised
                        var Listener = new Listener<System.ComponentModel.PropertyChangedEventArgs>();

                        Colony.PropertyChanged += Listener.Listen;

                        Colony.Shipyard = null; //Check we can now unset this value
                        Assert.IsNull(Colony.Shipyard);

                        Assert.AreEqual(1, Listener.ReceivedEvents.Count); //After setting the Shipyard null PropertyChanged should be raised
                    }
                }
            }
        }

        /// <summary>
        /// Colony::Buildings
        /// Check the Buildings Object is not not null
        /// </summary>
        [Test]
        public void testColonyBuildings()
        {
            foreach (var Colony in this.Colonies)
            {
                Assert.IsNotNull(Colony.Buildings);
                //I also want to make sure we cannot directly modify the Colony Collection
                Assert.IsTrue(Colony.Buildings.IsReadOnly);
            }
        }

        /// <summary>
        /// Colony::IsProductionAutomated
        /// Test the IsProductionAutomated property
        /// 
        /// If the owner is not human the property should always return true
        /// </summary>
        [Test]
        public void testColonyIsProductionAutomated()
        {
            using (var CTest = new ColonyTest())
            {
                foreach (var Colony in CTest.Colonies)
                {
                    //By Default...
                    //If the owner is AI the production should be automated
                    //If the owner is human the producation should not be automated
                    Assert.AreEqual(!Colony.Owner.IsHuman, Colony.IsProductionAutomated);

                    //Attempt to set the producation automated. 
                    //This should be true for all colonies
                    Colony.IsProductionAutomated = true;
                    Assert.IsTrue(Colony.IsProductionAutomated);

                    //Attempt IsProducationAutomated false
                    //IsProducationAutomated should only return false for human colonies
                    Colony.IsProductionAutomated = false;
                    Assert.AreEqual(Colony.Owner.IsHuman ? false : true, Colony.IsProductionAutomated);
                }
            }
         }

        /// <summary>
        /// Colony::ScrapBonus
        /// Test the ScrapBonus property
        /// 
        /// Each building (that is not being scrapped) potentially adds a scrap bouns.
        /// Check that the value we retrieve matches the the expected value
        /// 
        /// NOTE: Should morale modify the scrap bonus?
        /// </summary>
        [Test]
        public void testScrapBonus()
        {
            using (var CTest = new ColonyTest())
            {
                foreach (var Colony in CTest.Colonies)
                {
                    //Deactivate all buildings in this colony
                    foreach (var building in Colony.Buildings) { building.IsActive = false; }
                    //The scrap bouns should be zero
                    Assert.AreEqual(new Supremacy.Types.Percentage(0), Colony.ScrapBonus);

                    var Building = new Buildings.Building(GetDesign(0,
                        BonusType.PercentScrapping, 10));

                    //Lets add a basic scrap bonus
                    Colony.AddBuilding(Building);

                    Assert.AreEqual(new Supremacy.Types.Percentage(0.1), Colony.ScrapBonus);

                    //Let us now scrap this building. Our scrab bonus should again be zero
                    Building.Scrap = true;

                    Assert.AreEqual(new Supremacy.Types.Percentage(0), Colony.ScrapBonus);

                    //Now add a new building.
                    Colony.AddBuilding(new Buildings.Building(GetDesign(0,
                        BonusType.PercentScrapping, 20)));

                     Assert.AreEqual(new Supremacy.Types.Percentage(0.2), Colony.ScrapBonus);
                }
            }
        }

        /// <summary>
        /// Colony::TaxCredits
        /// Test the TaxCredits property
        /// </summary>
        [Test]
        [Ignore("TODO: Check these calculations.")]
        public void testTaxCredits()
        {
            using (var CTest = new ColonyTest())
            {
                foreach (var Colony in CTest.Colonies)
                {
                    //Disable all buildings
                    foreach (var building in Colony.Buildings) { building.IsActive = false; }

                    float moraleMod = Colony.Morale.CurrentValue / (0.5f * Supremacy.Game.MoraleHelper.MaxValue);

                    Assert.AreEqual((int)(moraleMod * Colony.Population.CurrentValue), Colony.TaxCredits);

                    //Now lets add some basic buildings that modify the Credits

                    //Firstly an irrelevant, but active building
                    Colony.AddBuilding(new Buildings.Building(GetDesign(0,
                        BonusType.AntiShipDefense, 0)));
                    Assert.AreEqual((int)(moraleMod * Colony.Population.CurrentValue), Colony.TaxCredits);

                    //Add a bonus of 10 credits
                    Colony.AddBuilding(new Buildings.Building(GetDesign(0,
                        BonusType.Credits, 10)));

                    Assert.AreEqual((int)(moraleMod * Colony.Population.CurrentValue) + 10, Colony.TaxCredits);

                    //Now add a % bonus
                    Colony.AddBuilding(new Buildings.Building(GetDesign(0,
                       BonusType.PercentCredits, 10)));

                    Assert.AreEqual((int)((moraleMod + 0.1) * Colony.Population.CurrentValue) + 10, Colony.TaxCredits);

                }
            }
        }

        #region Colony Production Output Test

        /// <summary>
        /// public int Colony::GetProductionOutput(ProductionCategory category)
        /// Test the GetProductionOutput method
        /// </summary>
        [Test]
        [Ignore("TODO: Check these calculations.")]
        public void testColonyGetProductionOutput()
        {
            using (var CTest = new ColonyTest())
            {
                foreach (var Colony in CTest.Colonies)
                {
                    foreach (ProductionCategory Category in Enum.GetValues(typeof(ProductionCategory)))
                    {
                        Supremacy.Types.OutputModifier modifier = Colony.GetProductionModifier(Category);
                        int baseOutput = Colony.GetFacilityType(Category).UnitOutput * Colony.GetActiveFacilities(Category);
                        if (Category == ProductionCategory.Food)
                            baseOutput += Colony.BaseFoodProduction;

                        if (Category == ProductionCategory.Industry)
                        {
                             baseOutput = (int)((Colony.Morale.CurrentValue / (0.5f * Supremacy.Game.MoraleHelper.MaxValue)) * baseOutput);
                        }

                        Assert.AreEqual((int)(baseOutput + (baseOutput * modifier.Efficiency)) + modifier.Bonus,
                            Colony.GetProductionOutput(Category));                        
                    }
                }
            }
        }

        /// <summary>
        /// public int Colony::GetFacilityType(ProductionCategory category)
        /// Test the GetFacilityType method
        /// </summary>
        [Test]
        public void testColonyGetFacilityType()
        {
            foreach (var Colony in this.Colonies)
            {
                foreach (ProductionCategory Category in Enum.GetValues(typeof(ProductionCategory)))
                { Assert.IsNotNull(Colony.GetFacilityType(Category)); }
            }
        }

        /// <summary>
        /// public int Colony::GetActiveFacilities(ProductionCategory category)
        /// Test the GetActiveFacilities method
        /// </summary>
        [Test]
        public void testColonyGetActiveFacilities()
        {
            foreach (var Colony in this.Colonies)
            {
                foreach (ProductionCategory Category in Enum.GetValues(typeof(ProductionCategory)))
                {
                    Assert.IsNotNull(Colony.GetActiveFacilities(Category));
                }
            }
        }

        /// <summary> 
        /// public int Colony::GetProductionModifier(ProductionCategory category)
        /// Test the GetProductionModifier method
        /// </summary>
        [Test]
        public void testColonyGetProductionModifier()
        {
            using (var CTest = new ColonyTest())
            {
                foreach (var Colony in CTest.Colonies)
                {
                    foreach (ProductionCategory Category in Enum.GetValues(typeof(ProductionCategory)))
                    {
                        //Firstly we are going to need to disable all buildings
                        foreach (var building in Colony.Buildings) { building.IsActive = false; }

                        Supremacy.Types.OutputModifier modifier = new Supremacy.Types.OutputModifier(0, 0.0f);

                        //Morale has a basic impact upon the Producation Modifier
                        Supremacy.Types.Percentage moraleMod =
// ReSharper disable PossibleLossOfFraction
                            (float)Colony.Morale.CurrentValue / (Supremacy.Game.MoraleHelper.MaxValue / 2);
// ReSharper restore PossibleLossOfFraction

                        switch (Category)
                        {
                            case ProductionCategory.Food:
                                //Each Planet in the system has a potential food bonus. If it does factor it in!

                                //The factor seems to be fixed at 15%
                                foreach (Planet planet in Colony.System.Planets)
                                { if (planet.HasFoodBonus) { modifier.Efficiency += 0.15f; } }

                                break;
                            case ProductionCategory.Energy:
                                foreach (Planet planet in Colony.System.Planets)
                                { if (planet.HasEnergyBonus) { modifier.Efficiency += 0.15f; } }

                                break;
                            case ProductionCategory.Industry:
                                modifier.Bonus += Colony.Population.CurrentValue;
                                break;
                        }

                        Assert.AreEqual(new Supremacy.Types.Percentage(modifier.Efficiency * moraleMod),
                                    Colony.GetProductionModifier(Category).Efficiency);
                        Assert.AreEqual(modifier.Bonus, Colony.GetProductionModifier(Category).Bonus);

                        // Now we must add some buildings that will apply an additional modification to the output
                        switch (Category)
                        {
                            case ProductionCategory.Energy:
                                Colony.AddBuilding(new Buildings.Building(GetDesign(0,
                                    BonusType.PercentEnergy, 10)));

                                Colony.AddBuilding(new Buildings.Building(GetDesign(0,
                                        BonusType.Energy, 10)));

                                modifier.Efficiency += 0.10f;
                                modifier.Bonus += 10;

                                break;
                            case ProductionCategory.Food:
                                Colony.AddBuilding(new Buildings.Building(GetDesign(0,
                                                      BonusType.PercentFood, 10)));

                                Colony.AddBuilding(new Buildings.Building(GetDesign(0,
                                        BonusType.Food, 10)));

                                modifier.Efficiency += 0.10f;
                                modifier.Bonus += 10;

                                break;
                            case ProductionCategory.Industry:
                                Colony.AddBuilding(new Buildings.Building(GetDesign(0,
                                               BonusType.PercentIndustry, 10)));

                                Colony.AddBuilding(new Buildings.Building(GetDesign(0,
                                        BonusType.Industry, 10)));

                                modifier.Efficiency += 0.10f;
                                modifier.Bonus += 10;

                                break;
                            case ProductionCategory.Intelligence:
                                Colony.AddBuilding(new Buildings.Building(GetDesign(0,
                                        BonusType.Intelligence, 10)));

                                modifier.Bonus += 10;

                                break;
                            case ProductionCategory.Personnel:
                                //No bonus added

                                break;
                            case ProductionCategory.Research:
                                Colony.AddBuilding(new Buildings.Building(GetDesign(0,
                                    BonusType.Research, 10)));

                                modifier.Bonus += 10;

                                break;
                        }

                        Assert.AreEqual(new Supremacy.Types.Percentage(modifier.Efficiency * moraleMod),
                            Colony.GetProductionModifier(Category).Efficiency);
                        Assert.AreEqual(modifier.Bonus, Colony.GetProductionModifier(Category).Bonus);

                    } // foreach (ProductionCategory Category in
                } // foreach (var Colony in this.Colonies)
            }
        } // testColonyGetProductionModifier

        #endregion 

        #region Colony Resource Production

        /// <summary> 
        /// Test public int GetResourceProduction(ResourceType resource)
        /// Truth be told this test is pretty pointless. It will just serve to add an addtional check if modifying the 
        /// underlying GetResourceProduction method for whatever reason.
        /// </summary>
        [Test]
        public void testColonyGetResourceProduction()
        {
            foreach (var Colony in this.Colonies)
            {
                foreach (ResourceType Resource in
                    Enum.GetValues(typeof(ResourceType)))
                {
                    var modifier = Colony.GetResourceModifier(Resource);
                    int baseValue = 0;

                    switch (Resource)
                    {
                        case ResourceType.Deuterium:
                            foreach (Planet planet in Colony.System.Planets)
                            {
                                if (planet.PlanetType == PlanetType.GasGiant) { baseValue += 10; }
                            }
                  
                            break;
                        //case ResourceType.Dilithium:
                        //    break;
                        case ResourceType.Personnel:

                        var personnelTable = Supremacy.Game.GameContext.Current.Tables.ResourceTables["BasePersonnel"];
                        if (personnelTable != null)
                        {
                            if (personnelTable[Colony.Owner.Key] != null)
                                baseValue = Supremacy.Types.Number.ParseInt32(personnelTable[Colony.Owner.Key][0]);
                            else
                                baseValue = Supremacy.Types.Number.ParseInt32(personnelTable[0][0]);
                            baseValue = (int)(0.01f * baseValue * Colony.Population.CurrentValue);
                        }
                            break;
                        case ResourceType.RawMaterials:
                            // Ineed to access this field through reflection
                            baseValue = (byte) Colony.GetType().GetField("_baseRawMaterials",
                                System.Reflection.BindingFlags.Instance | 
                                System.Reflection.BindingFlags.NonPublic).GetValue(Colony);

                            break;
                    }

                    Assert.AreEqual((int)(baseValue + (baseValue * modifier.Efficiency) + modifier.Bonus), 
                        Colony.GetResourceProduction(Resource), Resource.ToString());
                }
            }
        }

        /// <summary> 
        /// public OutputModifier GetResourceModifier(ResourceType resource)
        /// </summary>
        [Test]
        public void testColonyGetResourceModifier()
        {
            using (var CTest = new ColonyTest())
            {
                foreach (var Colony in CTest.Colonies)
                {
                    foreach (ResourceType Resource in 
                        Enum.GetValues(typeof(ResourceType)))
                    {
                        var modifier = new Supremacy.Types.OutputModifier(0, 0.0f);
                        //Disable all buildings
                        foreach (var building in Colony.Buildings) { building.IsActive = false; }

                        Assert.AreEqual(0, Colony.GetResourceModifier(Resource).Bonus);
                        Assert.AreEqual(new Supremacy.Types.Percentage(0), Colony.GetResourceModifier(Resource).Efficiency);

                        var BuildingDesign = GetDesign(0, BonusType.AntiShipDefense, 0);

                        Colony.AddBuilding(new Buildings.Building(BuildingDesign) );

                        switch (Resource)
                        {
                            case ResourceType.Deuterium:
                                BuildingDesign.Bonuses.Add(
                                    new Bonus(BonusType.Deuterium, 10));
                                BuildingDesign.Bonuses.Add(
                                    new Bonus(BonusType.PercentDeuterium, 10));

                                modifier.Efficiency += 0.1f;

                                break;
                            case ResourceType.Dilithium:
                                BuildingDesign.Bonuses.Add(
                                    new Bonus(BonusType.Dilithium, 10));
                            
                                break;
                            case ResourceType.Personnel:
                                BuildingDesign.Bonuses.Add(
                                    new Bonus(BonusType.Personnel, 10));

                                break;
                            case ResourceType.RawMaterials:
                                BuildingDesign.Bonuses.Add(
                                    new Bonus(BonusType.RawMaterials, 10));
                                BuildingDesign.Bonuses.Add(
                                    new Bonus(BonusType.PercentRawMaterials, 10));

                                modifier.Efficiency += 0.1f;

                                break;
                        }

                        modifier.Bonus += 10; //All ResourceTypes add the same bonus in this test

                        Assert.AreEqual(modifier.Bonus, Colony.GetResourceModifier(Resource).Bonus, Resource.ToString());
                        Assert.AreEqual(new Supremacy.Types.Percentage(modifier.Efficiency), 
                            Colony.GetResourceModifier(Resource).Efficiency);

                    }
                }
            }
        }

        #endregion


        /// <summary>
        /// test public int GetTotalFacilities(ProductionCategory category)
        /// Just make sure that the returned value is not null
        /// </summary>
        [Test]
        public void testColonyGetTotalFacilities()
        {
            foreach (var Colony in this.Colonies)
            {
                foreach (ProductionCategory Category in
                    Enum.GetValues(typeof(ProductionCategory)))
                { Assert.IsNotNull(Colony.GetTotalFacilities(Category)); }
            }
        }

        /// <summary>
        /// test public void SetFacilityType(ProductionCategory category, ProductionFacilityDesign design)
        /// </summary>
        [Test]
        public void testColonySetFacilityType()
        {
            using (var CTest = new ColonyTest())
            {
                foreach (var Colony in CTest.Colonies)
                {
                    foreach (ProductionCategory Category in
                        Enum.GetValues(typeof(ProductionCategory)))
                    {
                        Colony.SetFacilityType(Category, null);
                        //Note when accessing this value the return value is null
                        Assert.AreEqual(null, Colony.GetFacilityType(Category));

                        foreach (ProductionFacilityDesign FacilityDesign in
                             Supremacy.Game.GameContext.Current.TechDatabase.ProductionFacilityDesigns)
                        {
                            if (FacilityDesign.Category == Category)
                            {
                                Colony.SetFacilityType(Category, FacilityDesign);
                                Assert.AreEqual(FacilityDesign.DesignID, Colony.GetFacilityType(Category).DesignID);
                            }
                        }


                    }
                }
            }
        }

        /// <summary>
        /// test public void SetFacilityType(ProductionCategory category, ProductionFacilityDesign design)
        /// Check that if we are setting an invalid design we get an exception thrown!
        /// </summary>
        [Test]
        [ExpectedException(typeof(ArgumentException))]
        public void testColonySetFacilityTypeSetInvalidDesignCategory()
        {
            using (var CTest = new ColonyTest())
            {
                foreach (var Colony in CTest.Colonies)
                {
                    foreach (ProductionCategory Category in
                     Enum.GetValues(typeof(ProductionCategory)))
                    {
                        foreach (ProductionFacilityDesign FacilityDesign in
                             Supremacy.Game.GameContext.Current.TechDatabase.ProductionFacilityDesigns)
                        {
                            //At some point during this test we should get the expected exception raised
                            Colony.SetFacilityType(Category, FacilityDesign); 
                        }
                    }
                }
            }
        }

#region "Facility"

        /// <summary>
        /// test public bool ActivateFacility(ProductionCategory category)
        /// </summary>
        [Test]
        public void testColonyActivateFacility()
        {
            using (var CTest = new ColonyTest())
            {
#pragma warning disable 168
                foreach (var Colony in CTest.Colonies)
                {
                    //Colony.GetActiveFacilities(ProductionCategory.Industry)
                }
#pragma warning restore 168
            }
        }


#endregion


     }
}